/*
**  Copyright (C), CHENGDU GONGWEI TECHNOLOGY CO.,LTD.
**
**  Project:	Manager Unit v1.0
**  File:    	
**  Author: 	zhaozhuyu
**  Date:    	2017/05/20
**
**  Purpose:
**    		.
**
**  History: 
**  <author>   <time>          <version >   <desc>
*	$$Author$$
*/


/* Include files. */

extern "C" { 
	#include "standard.h"
	#include "util.h"
	#include "debug.h"
} 

#include "timercore.h"
#include "subsystemcore.h"
#include "cplusplus.h"

/* Local function declarations. */

/* Macro API definitions. */

/* Global variable declarations. */

#ifndef U_LOOP
extern struct ev_loop *main_loop;
#endif

/* Type definitions. */

/* Local function definitions. */

timer::timer()
{
    _b1 = false;
    _b2 = false;
}

void timer::start()
{
    gettimeofday(&_start, NULL); 
    _b1 = true;
    _b2 = false;
}

void timer::stop()
{ 
    if (_b1 == true){
        gettimeofday(&_end, NULL); 
        _b2 = true;
    }
}

void timer::reset()
{ 
    _b1 = false;
    _b2 = false;
}

void timer::costTime()
{
    if (_b1 == false) {
        return ;
    }
    else if (_b2 == false) {
        return ;
    }
    else {
        int usec, sec;
        bool borrow = false;
        if (_end.tv_usec > _start.tv_usec) {
            usec = _end.tv_usec - _start.tv_usec;
        }
        else {
            borrow = true;
            usec = _end.tv_usec + 1000000 - _start.tv_usec;
        }
        if (borrow) {
            sec = _end.tv_sec-1 - _start.tv_sec;
        }
        else {
            sec = _end.tv_sec - _start.tv_sec;
        }
        INFO("timer cost %ds, %dus\n", sec, usec);
    }
}

#ifdef U_LOOP
static void timeOutCallback(struct uloop_timeout *w)
#else
static void timeOutCallback(struct ev_loop *loop,
					ev_timer *w, int revents)
#endif
{
	timeObj *tobj = (timeObj *)w->data;
	tobj->_sub->sendSubSystem(tobj->_sub->_L, tobj->_sub->_name.c_str(), 
						"response", "", tobj->_session);
	tobj->_sub->removeTimeObj(tobj->_session);
	delete tobj;
}

int luaDeleteTime(lua_State *L)
{
	u32 session = lua_tointeger(L, 1);
	lua_getfield(L, LUA_REGISTRYINDEX, "sub");
	subSystem *sub = (subSystem*)lua_touserdata(L, -1);
	if (sub == NULL) {
		ERROR("subsystem error!");
		ASSERT(0);
		return 0;
	}
	timeObj *tobj = sub->findTimeObj(session);
	if (tobj != NULL) {
		sub->_time_obj_map.erase(tobj->_session);
		
#ifdef U_LOOP
		uloop_timeout_cancel(&tobj->_w);
#else
		ev_timer_stop(main_loop, &tobj->_w);
#endif
		delete tobj;
	}
	
	return 0;
}

int luaTimeout(lua_State *L)
{
	double time = lua_tonumber(L, 1);
	u32 session = lua_tointeger(L, 2);
	lua_getfield(L, LUA_REGISTRYINDEX, "sub");
	subSystem *sub = (subSystem*)lua_touserdata(L, -1);
	if (sub == NULL) {
		ERROR("subsystem error!");
		ASSERT(0);
		return 0;
	}
	timeObj *tobj = new timeObj();
	tobj->_session = session;
	tobj->_sub = sub;
	sub->_time_obj_map[session] = tobj;
	
#ifdef U_LOOP
	tobj->_w.cb = timeOutCallback;
	tobj->_w.data = (void*)tobj;
	uloop_timeout_set(&tobj->_w, time * 1000);
#else
	ev_timer_init(&tobj->_w, timeOutCallback, time, 0);
	tobj->_w.data = (void*)tobj;
	ev_timer_start(main_loop, &tobj->_w);
#endif

	lua_pushnumber(L, session);
	return 1;
}

u64 currentMsTime(void) 
{
	struct timespec time;
	clock_gettime(CLOCK_MONOTONIC, &time);
	return time.tv_sec * 1000000 + time.tv_nsec / 1000;
}

